﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using slwhTools.SLog;
using Serilog;
using Serilog.Events;
using Serilog.Formatting.Json;
using System.Xml.Linq;

namespace slwhTools.SLog
{
    public static class LoggingExtensions
    {
        //需要appsettings.json 配置信息
        public static IServiceCollection AddCustomSLogging(
            this IServiceCollection services,
            IConfiguration configuration,
            Action<LoggingOptions>? configure = null)
        {
            // 配置日志选项
            var options = new LoggingOptions();
            configuration.GetSection("Logging").Bind(options);
            configure?.Invoke(options);

            // 配置 Serilog
            var loggerConfig = new LoggerConfiguration()
                .MinimumLevel.Is(GetLogLevel(options.DefaultLogLevel))
                .Enrich.FromLogContext();

            // 应用日志级别覆盖
            foreach (var overrideConfig in options.OverrideLogLevels)
            {
                loggerConfig.MinimumLevel.Override(
                    overrideConfig.Key,
                    GetLogLevel(overrideConfig.Value));
            }

            // 配置输出目标
            foreach (var sink in options.Sinks)
            {
                switch (sink.Name.ToLower())
                {
                    case "console":
                        loggerConfig.WriteTo.Console(
                            restrictedToMinimumLevel: GetLogLevel(sink.Args.TryGetValue("restrictedToMinimumLevel", out var consoleLevel)
                                ? consoleLevel.ToString()
                                : options.DefaultLogLevel),
                            outputTemplate: sink.Args.TryGetValue("outputTemplate", out var consoleTemplate)
                                ? consoleTemplate.ToString()
                                : "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}");
                        break;

                    case "file":
                        loggerConfig.WriteTo.File(
                            path: sink.Args["path"].ToString(),
                            rollingInterval: sink.Args.TryGetValue("rollingInterval", out var interval)
                                ? Enum.Parse<RollingInterval>(interval.ToString()!)
                                : RollingInterval.Day,
                            restrictedToMinimumLevel: GetLogLevel(sink.Args.TryGetValue("restrictedToMinimumLevel", out var fileLevel)
                                ? fileLevel.ToString()
                                : options.DefaultLogLevel),
                            outputTemplate: sink.Args.TryGetValue("outputTemplate", out var fileTemplate)
                                ? fileTemplate.ToString()
                                : "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
                            retainedFileCountLimit: sink.Args.TryGetValue("retainedFileCountLimit", out var limit)
                                ? int.Parse(limit.ToString()!)
                                : null);
                        break;

                    case "jsonfile":
                        loggerConfig.WriteTo.File(
                            new JsonFormatter(),
                            sink.Args["path"].ToString(),
                            rollingInterval: sink.Args.TryGetValue("rollingInterval", out var jsonInterval)
                                ? Enum.Parse<RollingInterval>(jsonInterval.ToString()!)
                                : RollingInterval.Day,
                            restrictedToMinimumLevel: GetLogLevel(sink.Args.TryGetValue("restrictedToMinimumLevel", out var jsonLevel)
                                ? jsonLevel.ToString()
                                : options.DefaultLogLevel));
                        break;
                }
            }

            Log.Logger = loggerConfig.CreateLogger();

            // 清除默认日志提供程序，使用 Serilog
            services.AddLogging(loggingBuilder =>
                loggingBuilder.ClearProviders().AddSerilog(dispose: true));

            // 注册日志服务
            services.AddScoped(typeof(ISLogService<>), typeof(LogService<>));

            return services;
        }

        //初始化
        public static IServiceCollection AddSlog(this IServiceCollection services) {


            //Serilog.Log.Logger = new LoggerConfiguration()
            //   .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
            //   .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
            //   .Enrich.FromLogContext()
            //.WriteTo.Console()
            //   .WriteTo.File($"./logs/{DateTime.Now:yyyy-MM-dd}.txt", rollingInterval: RollingInterval.Day, rollOnFileSizeLimit: true, retainedFileCountLimit: 3)
            //   .CreateLogger();


            // 配置 Serilog
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Information)
                .MinimumLevel.Override("System", Serilog.Events.LogEventLevel.Warning)
                .Enrich.FromLogContext()
                .WriteTo.Console()
                .WriteTo.File(
                    path: $"logs/{DateTime.Now:yyyy-MM-dd}.txt",
                    fileSizeLimitBytes: 10_000_000, // 10MB
                    retainedFileCountLimit: 31,
                    outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
                .CreateLogger();


            // 清除默认日志提供程序，使用 Serilog
            services.AddLogging(loggingBuilder =>
                loggingBuilder.ClearProviders().AddSerilog(dispose: true));

            // 注册日志服务
            services.AddScoped(typeof(ISLogService<>), typeof(LogService<>));
            //services.AddTransient(typeof(ISLogService<>), typeof(LogService<>));
            return services;
        }

        private static LogEventLevel GetLogLevel(string level) => level.ToUpper() switch
        {
            "TRACE" => LogEventLevel.Verbose,
            "DEBUG" => LogEventLevel.Debug,
            "INFORMATION" => LogEventLevel.Information,
            "WARNING" => LogEventLevel.Warning,
            "ERROR" => LogEventLevel.Error,
            "CRITICAL" => LogEventLevel.Fatal,
            _ => LogEventLevel.Information
        };
    }
}
